<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1" />
<meta name="generator" content="pdoc 0.11.5" />
<title>pyboy.api.gameshark API documentation</title>
<meta name="description" content="" />
<link href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css' rel='stylesheet'>
<link href='https://cdnjs.cloudflare.com/ajax/libs/10up-sanitize.css/8.0.0/sanitize.min.css' rel='stylesheet'>
<link href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/styles/github.min.css" rel="stylesheet">
<style>.flex{display:flex !important}body{line-height:1.5em}#content{padding:20px}#sidebar{padding:30px;overflow:hidden}.http-server-breadcrumbs{font-size:130%;margin:0 0 15px 0}#footer{font-size:.75em;padding:5px 30px;border-top:1px solid #ddd;text-align:right}#footer p{margin:0 0 0 1em;display:inline-block}#footer p:last-child{margin-right:30px}h1,h2,h3,h4,h5{font-weight:300}h1{font-size:2.5em;line-height:1.1em}h2{font-size:1.75em;margin:1em 0 .50em 0}h3{font-size:1.4em;margin:25px 0 10px 0}h4{margin:0;font-size:105%}a{color:#058;text-decoration:none;transition:color .3s ease-in-out}a:hover{color:#e82}.title code{font-weight:bold}h2[id^="header-"]{margin-top:2em}.ident{color:#900}pre code{background:#f8f8f8;font-size:.8em;line-height:1.4em}code{background:#f2f2f1;padding:1px 4px;overflow-wrap:break-word}h1 code{background:transparent}pre{background:#f8f8f8;border:0;border-top:1px solid #ccc;border-bottom:1px solid #ccc;margin:1em 0;padding:1ex}#http-server-module-list{display:flex;flex-flow:column}#http-server-module-list div{display:flex}#http-server-module-list dt{min-width:10%}#http-server-module-list p{margin-top:0}.toc ul,#index{list-style-type:none;margin:0;padding:0}#index code{background:transparent}#index h3{border-bottom:1px solid #ddd}#index ul{padding:0}#index h4{font-weight:bold}#index h4 + ul{margin-bottom:.6em}@media (min-width:200ex){#index .two-column{column-count:2}}@media (min-width:300ex){#index .two-column{column-count:3}}dl{margin-bottom:2em}dl dl:last-child{margin-bottom:4em}dd{margin:0 0 1em 3em}#header-classes + dl > dd{margin-bottom:3em}dd dd{margin-left:2em}dd p{margin:10px 0}.name{background:#eee;font-weight:bold;font-size:.85em;padding:5px 10px;display:inline-block;min-width:40%}.name:hover{background:#e0e0e0}.name > span:first-child{white-space:nowrap}.name.class > span:nth-child(2){margin-left:.4em}.inherited{color:#999;border-left:5px solid #eee;padding-left:1em}.inheritance em{font-style:normal;font-weight:bold}.desc h2{font-weight:400;font-size:1.25em}.desc h3{font-size:1em}.desc dt code{background:inherit}.source summary,.git-link-div{color:#666;text-align:right;font-weight:400;font-size:.8em;text-transform:uppercase}.source summary > *{white-space:nowrap;cursor:pointer}.git-link{color:inherit;margin-left:1em}.source pre{max-height:500px;overflow:auto;margin:0}.source pre code{font-size:12px;overflow:visible}.hlist{list-style:none}.hlist li{display:inline}.hlist li:after{content:',\2002'}.hlist li:last-child:after{content:none}.hlist .hlist{display:inline;padding-left:1em}img{max-width:100%}.admonition{padding:.1em .5em;margin-bottom:1em}.admonition-title{font-weight:bold}.admonition.note,.admonition.info,.admonition.important{background:#aef}.admonition.todo,.admonition.versionadded,.admonition.tip,.admonition.hint{background:#dfd}.admonition.warning,.admonition.versionchanged,.admonition.deprecated{background:#fd4}.admonition.error,.admonition.danger,.admonition.caution{background:lightpink}</style>
<style media="screen and (min-width: 700px)">@media screen and (min-width:700px){#sidebar{width:30%}#content{width:70%;max-width:100ch;padding:3em 4em;border-left:1px solid #ddd}pre code{font-size:0.8em}.item .name{font-size:1em}main{display:flex;flex-direction:row-reverse;justify-content:flex-end}.toc ul ul,#index ul{padding-left:1.5em}.toc > ul > li{margin-top:.5em}}</style>
<style media="print">@media print{#sidebar h1{page-break-before:always}.source{display:none}}@media print{*{background:transparent !important;color:#000 !important;box-shadow:none !important;text-shadow:none !important}a[href]:after{content:" (" attr(href) ")";font-size:90%}a[href][title]:after{content:none}abbr[title]:after{content:" (" attr(title) ")"}.ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:""}pre,blockquote{border:1px solid #999;page-break-inside:avoid}thead{display:table-header-group}tr,img{page-break-inside:avoid}img{max-width:100% !important}@page{margin:0.5cm}p,h2,h3{orphans:3;widows:3}h1,h2,h3,h4,h5,h6{page-break-after:avoid}}</style>
<script async src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?config=TeX-AMS_CHTML'></script>
</head>
<body>
<main>
<article id="content">
<header>
<h1 class="title">Module <code>pyboy.api.gameshark</code></h1>
</header>
<section id="section-intro">
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">#
# License: See LICENSE.md file
# GitHub: https://github.com/Baekalfen/PyBoy
#

from pyboy.logging import get_logger
from pyboy.utils import PyBoyInvalidInputException

logger = get_logger(__name__)

__pdoc__ = {
    &#34;GameShark.tick&#34;: False,
}


class GameShark:
    def __init__(self, memory):
        self.memory = memory
        self.cheats = {}
        self.enabled = False

    def _convert_cheat(self, gameshark_code):
        &#34;&#34;&#34;
        A GameShark code for these consoles is written in the format ttvvaaaa. tt specifies the type, which is usually 01.
        vv specifies the hexadecimal value the code will write into the game&#39;s memory. aaaa specifies the memory address
        that will be modified, with the low byte first (e.g. address C056 is written as 56C0).
        Example 011556C0 would output:
        type = 01
        value = 0x15
        address = 0x56C0

        For more details:
        https://doc.kodewerx.org/hacking_gb.html

        There seems to be conflicting information about the presence of other types than 01.
        &#34;&#34;&#34;
        # Check if the input cheat code has the correct length (8 characters)
        if len(gameshark_code) != 8:
            raise ValueError(&#34;Invalid cheat code length. Cheat code must be 8 characters long.&#34;)

        # Extract components from the cheat code
        _type = int(gameshark_code[:2], 16)
        value = int(gameshark_code[2:4], 16)  # Convert hexadecimal value to an integer
        unconverted_address = gameshark_code[4:]  # Ex:   1ED1
        lower = unconverted_address[:2]  # Ex:  1E
        upper = unconverted_address[2:]  # Ex:  D1
        address_converted = upper + lower  # Ex: 0xD11E   # Converting to Ram Readable address
        address = int(address_converted, 16)

        if not 0x8000 &lt;= address:
            raise ValueError(&#34;Invalid GameShark code provided. Address not in the RAM range&#34;)

        return (_type, value, address)

    def _get_value(self, _type, address):
        if _type == 0x01:
            # 8-bit RAM write
            # Writes the byte xx to the address zzyy.
            return self.memory[address]
        # elif (_type &amp; 0xF0) == 0x80:
        #     # 8-bit RAM write (with bank change)
        #     # Changes the RAM bank to b, then writes the byte xx to the address zzyy.
        #     bank = _type &amp; 0xF
        #     pass
        # elif (_type &amp; 0xF0) == 0x90:
        #     # 8-bit RAM write (with WRAM bank change)
        #     # Changes the WRAM bank to b and then writes the byte xx to the address zzyy. GBC only.
        #     bank = _type &amp; 0xF
        #     pass
        else:
            raise ValueError(&#34;Invalid GameShark type&#34;, _type)

    def _set_value(self, _type, value, address):
        if _type == 0x01:
            # 8-bit RAM write
            # Writes the byte xx to the address zzyy.
            self.memory[address] = value
        # elif (_type &amp; 0xF0) == 0x80:
        #     # 8-bit RAM write (with bank change)
        #     # Changes the RAM bank to b, then writes the byte xx to the address zzyy.
        #     bank = _type &amp; 0xF
        #     pass
        # elif (_type &amp; 0xF0) == 0x90:
        #     # 8-bit RAM write (with WRAM bank change)
        #     # Changes the WRAM bank to b and then writes the byte xx to the address zzyy. GBC only.
        #     bank = _type &amp; 0xF
        #     pass
        else:
            raise ValueError(&#34;Invalid GameShark type&#34;, _type)

    def add(self, code):
        &#34;&#34;&#34;
        Add a GameShark cheat to the emulator.

        Example:
        ```python
        &gt;&gt;&gt; pyboy.gameshark.add(&#34;01FF16D0&#34;)
        ```

        Args:
            code (str): GameShark code to add
        &#34;&#34;&#34;
        self.enabled = True
        _type, value, address = self._convert_cheat(code)
        if code not in self.cheats:
            self.cheats[code] = (self._get_value(_type, address), (_type, value, address))
        else:
            raise PyBoyInvalidInputException(&#34;GameShark code already applied!&#34;)

    def remove(self, code, restore_value=True):
        &#34;&#34;&#34;
        Remove a GameShark cheat from the emulator.

        Example:
        ```python
        &gt;&gt;&gt; pyboy.gameshark.add(&#34;01FF16D0&#34;)
        &gt;&gt;&gt; pyboy.gameshark.remove(&#34;01FF16D0&#34;)
        ```

        Args:
            code (str): GameShark code to remove
            restore_value (bool): True to restore original value at address, otherwise don&#39;t restore
        &#34;&#34;&#34;

        if code not in self.cheats:
            raise ValueError(&#34;GameShark code cannot be removed. Hasn&#39;t been applied.&#34;)

        original_value, (_type, _, address) = self.cheats.pop(code)
        if restore_value:
            self._set_value(_type, original_value, address)

        if len(self.cheats) == 0:
            self.enabled = False

    def clear_all(self, restore_value=True):
        &#34;&#34;&#34;
        Remove all GameShark cheats from the emulator.

        Example:
        ```python
        &gt;&gt;&gt; pyboy.gameshark.clear_all()
        ```

        Args:
            restore_value (bool): Restore the original values of the memory addresses that were modified by the cheats.
        &#34;&#34;&#34;
        # NOTE: Create a list so we don&#39;t remove from the iterator we are going through
        for code in list(self.cheats.keys()):
            self.remove(code, restore_value)

    def tick(self):
        if not self.enabled:
            return 0
        # https://gbdev.io/pandocs/Shark_Cheats.html
        # &#34;As far as it is understood, patching is implemented by hooking the original VBlank interrupt handler, and
        # re-writing RAM values each frame.&#34;
        for _, (_, (_type, value, address)) in self.cheats.items():
            self._set_value(_type, value, address)</code></pre>
</details>
</section>
<section>
</section>
<section>
</section>
<section>
</section>
<section>
<h2 class="section-title" id="header-classes">Classes</h2>
<dl>
<dt id="pyboy.api.gameshark.GameShark"><code class="flex name class">
<span>class <span class="ident">GameShark</span></span>
<span>(</span><span>memory)</span>
</code></dt>
<dd>
<section class="desc"></section>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">class GameShark:
    def __init__(self, memory):
        self.memory = memory
        self.cheats = {}
        self.enabled = False

    def _convert_cheat(self, gameshark_code):
        &#34;&#34;&#34;
        A GameShark code for these consoles is written in the format ttvvaaaa. tt specifies the type, which is usually 01.
        vv specifies the hexadecimal value the code will write into the game&#39;s memory. aaaa specifies the memory address
        that will be modified, with the low byte first (e.g. address C056 is written as 56C0).
        Example 011556C0 would output:
        type = 01
        value = 0x15
        address = 0x56C0

        For more details:
        https://doc.kodewerx.org/hacking_gb.html

        There seems to be conflicting information about the presence of other types than 01.
        &#34;&#34;&#34;
        # Check if the input cheat code has the correct length (8 characters)
        if len(gameshark_code) != 8:
            raise ValueError(&#34;Invalid cheat code length. Cheat code must be 8 characters long.&#34;)

        # Extract components from the cheat code
        _type = int(gameshark_code[:2], 16)
        value = int(gameshark_code[2:4], 16)  # Convert hexadecimal value to an integer
        unconverted_address = gameshark_code[4:]  # Ex:   1ED1
        lower = unconverted_address[:2]  # Ex:  1E
        upper = unconverted_address[2:]  # Ex:  D1
        address_converted = upper + lower  # Ex: 0xD11E   # Converting to Ram Readable address
        address = int(address_converted, 16)

        if not 0x8000 &lt;= address:
            raise ValueError(&#34;Invalid GameShark code provided. Address not in the RAM range&#34;)

        return (_type, value, address)

    def _get_value(self, _type, address):
        if _type == 0x01:
            # 8-bit RAM write
            # Writes the byte xx to the address zzyy.
            return self.memory[address]
        # elif (_type &amp; 0xF0) == 0x80:
        #     # 8-bit RAM write (with bank change)
        #     # Changes the RAM bank to b, then writes the byte xx to the address zzyy.
        #     bank = _type &amp; 0xF
        #     pass
        # elif (_type &amp; 0xF0) == 0x90:
        #     # 8-bit RAM write (with WRAM bank change)
        #     # Changes the WRAM bank to b and then writes the byte xx to the address zzyy. GBC only.
        #     bank = _type &amp; 0xF
        #     pass
        else:
            raise ValueError(&#34;Invalid GameShark type&#34;, _type)

    def _set_value(self, _type, value, address):
        if _type == 0x01:
            # 8-bit RAM write
            # Writes the byte xx to the address zzyy.
            self.memory[address] = value
        # elif (_type &amp; 0xF0) == 0x80:
        #     # 8-bit RAM write (with bank change)
        #     # Changes the RAM bank to b, then writes the byte xx to the address zzyy.
        #     bank = _type &amp; 0xF
        #     pass
        # elif (_type &amp; 0xF0) == 0x90:
        #     # 8-bit RAM write (with WRAM bank change)
        #     # Changes the WRAM bank to b and then writes the byte xx to the address zzyy. GBC only.
        #     bank = _type &amp; 0xF
        #     pass
        else:
            raise ValueError(&#34;Invalid GameShark type&#34;, _type)

    def add(self, code):
        &#34;&#34;&#34;
        Add a GameShark cheat to the emulator.

        Example:
        ```python
        &gt;&gt;&gt; pyboy.gameshark.add(&#34;01FF16D0&#34;)
        ```

        Args:
            code (str): GameShark code to add
        &#34;&#34;&#34;
        self.enabled = True
        _type, value, address = self._convert_cheat(code)
        if code not in self.cheats:
            self.cheats[code] = (self._get_value(_type, address), (_type, value, address))
        else:
            raise PyBoyInvalidInputException(&#34;GameShark code already applied!&#34;)

    def remove(self, code, restore_value=True):
        &#34;&#34;&#34;
        Remove a GameShark cheat from the emulator.

        Example:
        ```python
        &gt;&gt;&gt; pyboy.gameshark.add(&#34;01FF16D0&#34;)
        &gt;&gt;&gt; pyboy.gameshark.remove(&#34;01FF16D0&#34;)
        ```

        Args:
            code (str): GameShark code to remove
            restore_value (bool): True to restore original value at address, otherwise don&#39;t restore
        &#34;&#34;&#34;

        if code not in self.cheats:
            raise ValueError(&#34;GameShark code cannot be removed. Hasn&#39;t been applied.&#34;)

        original_value, (_type, _, address) = self.cheats.pop(code)
        if restore_value:
            self._set_value(_type, original_value, address)

        if len(self.cheats) == 0:
            self.enabled = False

    def clear_all(self, restore_value=True):
        &#34;&#34;&#34;
        Remove all GameShark cheats from the emulator.

        Example:
        ```python
        &gt;&gt;&gt; pyboy.gameshark.clear_all()
        ```

        Args:
            restore_value (bool): Restore the original values of the memory addresses that were modified by the cheats.
        &#34;&#34;&#34;
        # NOTE: Create a list so we don&#39;t remove from the iterator we are going through
        for code in list(self.cheats.keys()):
            self.remove(code, restore_value)

    def tick(self):
        if not self.enabled:
            return 0
        # https://gbdev.io/pandocs/Shark_Cheats.html
        # &#34;As far as it is understood, patching is implemented by hooking the original VBlank interrupt handler, and
        # re-writing RAM values each frame.&#34;
        for _, (_, (_type, value, address)) in self.cheats.items():
            self._set_value(_type, value, address)</code></pre>
</details>
<h3>Methods</h3>
<dl>
<dt id="pyboy.api.gameshark.GameShark.add"><code class="name flex">
<span>def <span class="ident">add</span></span>(<span>self, code)</span>
</code></dt>
<dd>
<section class="desc"><p>Add a GameShark cheat to the emulator.</p>
<p>Example:</p>
<pre><code class="language-python">&gt;&gt;&gt; pyboy.gameshark.add(&quot;01FF16D0&quot;)
</code></pre>
<h2 id="args">Args</h2>
<dl>
<dt><strong><code>code</code></strong> :&ensp;<code>str</code></dt>
<dd>GameShark code to add</dd>
</dl></section>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def add(self, code):
    &#34;&#34;&#34;
    Add a GameShark cheat to the emulator.

    Example:
    ```python
    &gt;&gt;&gt; pyboy.gameshark.add(&#34;01FF16D0&#34;)
    ```

    Args:
        code (str): GameShark code to add
    &#34;&#34;&#34;
    self.enabled = True
    _type, value, address = self._convert_cheat(code)
    if code not in self.cheats:
        self.cheats[code] = (self._get_value(_type, address), (_type, value, address))
    else:
        raise PyBoyInvalidInputException(&#34;GameShark code already applied!&#34;)</code></pre>
</details>
</dd>
<dt id="pyboy.api.gameshark.GameShark.remove"><code class="name flex">
<span>def <span class="ident">remove</span></span>(<span>self, code, restore_value=True)</span>
</code></dt>
<dd>
<section class="desc"><p>Remove a GameShark cheat from the emulator.</p>
<p>Example:</p>
<pre><code class="language-python">&gt;&gt;&gt; pyboy.gameshark.add(&quot;01FF16D0&quot;)
&gt;&gt;&gt; pyboy.gameshark.remove(&quot;01FF16D0&quot;)
</code></pre>
<h2 id="args">Args</h2>
<dl>
<dt><strong><code>code</code></strong> :&ensp;<code>str</code></dt>
<dd>GameShark code to remove</dd>
<dt><strong><code>restore_value</code></strong> :&ensp;<code>bool</code></dt>
<dd>True to restore original value at address, otherwise don't restore</dd>
</dl></section>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def remove(self, code, restore_value=True):
    &#34;&#34;&#34;
    Remove a GameShark cheat from the emulator.

    Example:
    ```python
    &gt;&gt;&gt; pyboy.gameshark.add(&#34;01FF16D0&#34;)
    &gt;&gt;&gt; pyboy.gameshark.remove(&#34;01FF16D0&#34;)
    ```

    Args:
        code (str): GameShark code to remove
        restore_value (bool): True to restore original value at address, otherwise don&#39;t restore
    &#34;&#34;&#34;

    if code not in self.cheats:
        raise ValueError(&#34;GameShark code cannot be removed. Hasn&#39;t been applied.&#34;)

    original_value, (_type, _, address) = self.cheats.pop(code)
    if restore_value:
        self._set_value(_type, original_value, address)

    if len(self.cheats) == 0:
        self.enabled = False</code></pre>
</details>
</dd>
<dt id="pyboy.api.gameshark.GameShark.clear_all"><code class="name flex">
<span>def <span class="ident">clear_all</span></span>(<span>self, restore_value=True)</span>
</code></dt>
<dd>
<section class="desc"><p>Remove all GameShark cheats from the emulator.</p>
<p>Example:</p>
<pre><code class="language-python">&gt;&gt;&gt; pyboy.gameshark.clear_all()
</code></pre>
<h2 id="args">Args</h2>
<dl>
<dt><strong><code>restore_value</code></strong> :&ensp;<code>bool</code></dt>
<dd>Restore the original values of the memory addresses that were modified by the cheats.</dd>
</dl></section>
<details class="source">
<summary>
<span>Expand source code</span>
</summary>
<pre><code class="python">def clear_all(self, restore_value=True):
    &#34;&#34;&#34;
    Remove all GameShark cheats from the emulator.

    Example:
    ```python
    &gt;&gt;&gt; pyboy.gameshark.clear_all()
    ```

    Args:
        restore_value (bool): Restore the original values of the memory addresses that were modified by the cheats.
    &#34;&#34;&#34;
    # NOTE: Create a list so we don&#39;t remove from the iterator we are going through
    for code in list(self.cheats.keys()):
        self.remove(code, restore_value)</code></pre>
</details>
</dd>
</dl>
</dd>
</dl>
</section>
</article>
<nav id="sidebar">
<h1>Index</h1>
<div class="toc">
<ul></ul>
</div>
<ul id="index">
<li><h3>Super-module</h3>
<ul>
<li><code><a title="pyboy.api" href="index.html">pyboy.api</a></code></li>
</ul>
</li>
<li><h3><a href="#header-classes">Classes</a></h3>
<ul>
<li>
<h4><code><a title="pyboy.api.gameshark.GameShark" href="#pyboy.api.gameshark.GameShark">GameShark</a></code></h4>
<ul class="">
<li><code><a title="pyboy.api.gameshark.GameShark.add" href="#pyboy.api.gameshark.GameShark.add">add</a></code></li>
<li><code><a title="pyboy.api.gameshark.GameShark.remove" href="#pyboy.api.gameshark.GameShark.remove">remove</a></code></li>
<li><code><a title="pyboy.api.gameshark.GameShark.clear_all" href="#pyboy.api.gameshark.GameShark.clear_all">clear_all</a></code></li>
</ul>
</li>
</ul>
</li>
</ul>
</nav>
</main>
<footer id="footer">
<p>Generated by <a href="https://pdoc3.github.io/pdoc"><cite>pdoc</cite> 0.11.5</a>.</p>
</footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad()</script>
</body>
</html>
